package com.ruicar.afs.cloud.afscase.mq.receiver.processor;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.ruicar.afs.cloud.afscase.approveocr.entity.ApproveOcrBatch;
import com.ruicar.afs.cloud.afscase.approveocr.service.ApproveOcrBatchService;
import com.ruicar.afs.cloud.afscase.approvetask.entity.CaseApproveRecord;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkProcessScheduleInfo;
import com.ruicar.afs.cloud.afscase.approvetask.entity.WorkTaskPool;
import com.ruicar.afs.cloud.afscase.approvetask.service.CaseApproveRecordService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkProcessScheduleInfoService;
import com.ruicar.afs.cloud.afscase.approvetask.service.WorkTaskPoolService;
import com.ruicar.afs.cloud.afscase.common.utils.Const;
import com.ruicar.afs.cloud.afscase.infomanagement.entity.CaseBaseInfo;
import com.ruicar.afs.cloud.afscase.infomanagement.service.CaseBaseInfoService;
import com.ruicar.afs.cloud.afscase.message.entity.CaseNoticeInfo;
import com.ruicar.afs.cloud.afscase.message.service.CaseNoticeInfoService;
import com.ruicar.afs.cloud.afscase.mq.approvesendinfo.service.ApproveInformInfoService;
import com.ruicar.afs.cloud.afscase.processor.enums.WorkflowType;
import com.ruicar.afs.cloud.afscase.processor.service.ApproveWorkflowService;
import com.ruicar.afs.cloud.afscase.processor.vo.NormalTaskSubmitVO;
import com.ruicar.afs.cloud.afscase.step.entity.CaseStepParam;
import com.ruicar.afs.cloud.afscase.step.service.CaseStepParamService;
import com.ruicar.afs.cloud.common.core.enums.AfsEnumUtil;
import com.ruicar.afs.cloud.common.modules.afscorebusiness.enums.*;
import com.ruicar.afs.cloud.common.modules.dto.mq.approve.CallBackApplyDto;
import com.ruicar.afs.cloud.common.mq.rabbit.listener.AfsMqBizProcessor;
import com.ruicar.afs.cloud.common.mq.rabbit.message.MqTransCode;
import com.ruicar.afs.cloud.workflow.api.dto.flowprocess.WorkFlowResponse;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * <p>Description：</p>
 * 经销商撤回申请MQ消息接收处理类
 * @author ma_xueyu
 * @version 1.0
 * @createDate 2020-08-30
 */
@AllArgsConstructor
@Slf4j
@Component
public class CallBackApplyProcessor implements AfsMqBizProcessor<CallBackApplyDto> {

    private final CaseBaseInfoService caseBaseInfoService;
    private final WorkProcessScheduleInfoService workProcessScheduleInfoService;
    private final WorkTaskPoolService workTaskPoolService;
    private final CaseNoticeInfoService caseNoticeInfoService;
    private final ApproveWorkflowService approveWorkflowService;
    private final ApproveInformInfoService approveInformInfoService;
    private final CaseApproveRecordService caseApproveRecordService;
    private final ApproveOcrBatchService approveOcrBatchService;
    private final CaseStepParamService caseStepParamService;

    @Override
    public boolean processMessage(CallBackApplyDto callBackApplyDto) throws Exception {
        this.CallBackApplyQueue(callBackApplyDto);
        return true;
    }

    @Override
    public MqTransCode getCode() {
        return MqTransCode.AFS_POS_APPLY_CASE_CTM_CALL_BACK;
    }

    @Transactional(rollbackFor = Exception.class)
    public void CallBackApplyQueue(CallBackApplyDto callBackApplyDto) throws Exception {
        log.info("接收经销商撤回申请信息："+ JSON.toJSONString(callBackApplyDto));
        try {
            CaseBaseInfo caseBaseInfo = caseBaseInfoService.getOne(Wrappers.<CaseBaseInfo>query().lambda()
                    .eq(CaseBaseInfo::getApplyNo, callBackApplyDto.getApplyNo()));
            String lastBusinessStateIn = caseBaseInfo.getBusinessStateIn();
            List<String> normalWorkflowTypes = new ArrayList<>();
            normalWorkflowTypes.add(WorkflowType.NORMAL_NEW.getAfsFlowKey());
            normalWorkflowTypes.add(WorkflowType.NORMAL_OLD.getAfsFlowKey());
            WorkProcessScheduleInfo workProcessScheduleInfo = null;
            WorkTaskPool workTaskPool = null;
            List<WorkProcessScheduleInfo> workProcessScheduleList = workProcessScheduleInfoService.list(
                    Wrappers.<WorkProcessScheduleInfo>lambdaQuery()
                    .in(WorkProcessScheduleInfo::getAfsFlowKey,normalWorkflowTypes)
                    .eq(WorkProcessScheduleInfo::getApplyNo,callBackApplyDto.getApplyNo())
                    .orderByDesc(WorkProcessScheduleInfo::getCreateTime));
            if(CollectionUtil.isNotEmpty(workProcessScheduleList)){
                //获取最新流程实例
                workProcessScheduleInfo = workProcessScheduleList.get(0);
                List<WorkTaskPool> workTaskPoolList = workTaskPoolService.getWorkTaskListByCondition(callBackApplyDto.getApplyNo(),workProcessScheduleInfo.getId().toString());
                if(CollectionUtil.isNotEmpty(workTaskPoolList)){
                    if(workTaskPoolList.size()>1){
                        //任务已经过流程流转，无法撤回
                        approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.FALSE),lastBusinessStateIn);
                        return;
                    }
                    //获取首个任务信息
                    workTaskPool = workTaskPoolList.get(0);
                }
            }
            //判断是否为经销商重试撤回
            if(AfsEnumUtil.key(BusinessStateInEnum.DRAFT).equals(lastBusinessStateIn)||AfsEnumUtil.key(BusinessStateInEnum.CALL_BACK_WAIT_SUBMIT).equals(lastBusinessStateIn)){
                //通知进件系统撤回成功
                approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.TRUE),lastBusinessStateIn);
            }
            //流程外撤回
            else if(ObjectUtil.isNull(workTaskPool)
                    ||AfsEnumUtil.key(BusinessStateInEnum.TASK_ASSIGN).equals(caseBaseInfo.getBusinessStateIn())){
                //流程外撤回校验
                if(!this.checkCallBackDataBeforeWorkFlow(caseBaseInfo)){
                    //通知进件系统撤回失败
                    approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.FALSE),lastBusinessStateIn);
                }else{
                    log.info("*******工作流未分配任务经销商直接撤回，申请编号：{}*******",caseBaseInfo.getApplyNo());
                    //(1)、未分配工作流，将状态修改为：草稿
                    caseBaseInfo.setBusinessStateIn(AfsEnumUtil.key(BusinessStateInEnum.DRAFT));
                    caseBaseInfo.setWorkflowPrevStep(0);
                    caseBaseInfoService.updateById(caseBaseInfo);
                    CaseApproveRecord record = new CaseApproveRecord();
                    record.setApplyNo(callBackApplyDto.getApplyNo());
                    record.setUseScene(UseSceneEnum.APPROVE.getValue());
                    record.setDisposeStaff(callBackApplyDto.getApplyReporter());
                    record.setApproveSuggest(AfsEnumUtil.key(CallBackTypeEnum.WORKFLOW_APPLY));
                    record.setApproveSuggestName(AfsEnumUtil.desc(CallBackTypeEnum.WORKFLOW_APPLY));
                    record.setApproveEndTime(new Date());
                    record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
                    record.setApproveRemark(callBackApplyDto.getCallBackReason());
                    caseApproveRecordService.save(record);
                    //删除OCR记录
                    this.removeApproveOcrRecord(callBackApplyDto.getApplyNo());
                    //通知进件系统撤回成功
                    approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.TRUE),lastBusinessStateIn);
                }
            }else{//流程内撤回
                if(WhetherEnum.YES.getCode().equals(workTaskPool.getIsOpen())){
                    log.info("*******审批员已打开，保存经销商撤回通知消息，申请编号：{}*******",caseBaseInfo.getApplyNo());
                    CaseNoticeInfo caseNoticeInfo = new CaseNoticeInfo();
                    caseNoticeInfo.setApplyNo(callBackApplyDto.getApplyNo());
                    caseNoticeInfo.setNoticeType(AfsEnumUtil.key(CallBackTypeEnum.WORKFLOW_APPLY));
                    caseNoticeInfo.setNotice("经销商【"+callBackApplyDto.getChannelName()+"】申请撤回提交，原因："+callBackApplyDto.getCallBackReason());
                    caseNoticeInfo.setSendBy(callBackApplyDto.getApplyReporter());
                    caseNoticeInfo.setReceivedBy(workTaskPool.getApproveStaff());
                    caseNoticeInfo.setIsRead(AfsEnumUtil.key(ReadEnum.UNREAD));
                    caseNoticeInfoService.save(caseNoticeInfo);
                }else{
                    log.info("*******审批员未打开，执行废弃流程*******");
                    CaseApproveRecord record = new CaseApproveRecord();
                    record.setApplyNo(callBackApplyDto.getApplyNo());
                    record.setStageId(workTaskPool.getStageId());
                    record.setUseScene(UseSceneEnum.APPROVE.getValue());
                    record.setDisposeStaff(callBackApplyDto.getApplyReporter());
                    record.setApproveSuggest(AfsEnumUtil.key(CallBackTypeEnum.WORKFLOW_APPLY));
                    record.setApproveSuggestName(AfsEnumUtil.desc(CallBackTypeEnum.WORKFLOW_APPLY));
                    record.setApproveEndTime(new Date());
                    record.setApproveType(ApproveTypeEnum.PROCESS.getValue());
                    record.setApproveRemark(callBackApplyDto.getCallBackReason());
                    NormalTaskSubmitVO submitVO = NormalTaskSubmitVO.builder()
                            .record(record)
                            .workFlowInfo(workProcessScheduleInfo)
                            .workTaskPool(workTaskPool)
                            .build();
                    WorkFlowResponse workFlowResponse = approveWorkflowService.dealerCallBackFlow(submitVO);
                    if (Const.WORKFLOW_RESPONSE_SUCCESS == workFlowResponse.getSuccess()) {
                        //(2)、流程内撤回，修改案件业务状态为撤回待提交
                        caseBaseInfo.setBusinessStateIn(AfsEnumUtil.key(BusinessStateInEnum.CALL_BACK_WAIT_SUBMIT));
                        caseBaseInfo.setWorkflowPrevStep(0);
                        caseBaseInfoService.updateById(caseBaseInfo);
                        log.info("通知进件系统撤回成功，申请编号：{}*******",caseBaseInfo.getApplyNo());
                        approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.TRUE),lastBusinessStateIn);
                    }else{
                        log.info("通知进件系统撤回失败，申请编号：{}*******",caseBaseInfo.getApplyNo());
                        approveInformInfoService.submitCallBackResult(caseBaseInfo.getApplyNo(),AfsEnumUtil.key(ResultBooleanEnum.FALSE),lastBusinessStateIn);
                    }
                }
            }

        } catch (Exception e) {
            log.error("经销商撤回申请消息处理失败", e);
            throw e;
        }
    }

    /**
     * 流程外经销商撤回校验
     * @return true:可以撤回；false:不可直接撤回，需等待下次重试
     * */
    private Boolean checkCallBackDataBeforeWorkFlow(CaseBaseInfo caseBaseInfo){
        Boolean checkResult=true;
        if(AfsEnumUtil.key(BusinessStateInEnum.WAIT_QUERY).equals(caseBaseInfo.getBusinessStateIn())
                ||AfsEnumUtil.key(BusinessStateInEnum.TASK_ASSIGNING).equals(caseBaseInfo.getBusinessStateIn())){
            //查询玄武数据阶段\分配中状态  不可撤回
            checkResult = false;
        }
        return checkResult;
    }

    /**
     * 删除OCR记录
     * @param applyNo
     * */
    private void removeApproveOcrRecord(String applyNo){
        //删除OCR记录
        List<ApproveOcrBatch> approveOcrBatchList = approveOcrBatchService.list(Wrappers.<ApproveOcrBatch>query().lambda()
                .eq(ApproveOcrBatch::getApplyNo,applyNo)
                .orderByDesc(ApproveOcrBatch::getCreateTime));
        if(CollectionUtil.isNotEmpty(approveOcrBatchList)){
            ApproveOcrBatch approveOcrBatch = approveOcrBatchList.get(0);
            approveOcrBatchService.removeById(approveOcrBatch.getId());
        }
        List<CaseStepParam> caseStepParamList = caseStepParamService.list(Wrappers.<CaseStepParam>query().lambda()
                .eq(CaseStepParam::getApplyNo,applyNo));
        ArrayList<Long> idsArr = Lists.newArrayList();
        caseStepParamList.forEach(c -> {
            idsArr.add(c.getId());
        });
        caseStepParamService.removeByIds(idsArr);
    }
}
